from typing import Any
import httpx  # 异步HTTP请求
from mcp.server.fastmcp import FastMCP

# 使用FastMCP框架创建服务器
mcp = FastMCP("weather", log_level="ERROR")

# 美国国家气象局 API 的基础 URL
NWS_API_BASE = "https://api.weather.gov"   # 美国气象局地址
USER_AGENT = "weather-app/1.0 (contact@example.com)"  # 设置 User-Agent 头信息

'''
请求天气数据
传入: 请求url
'''
async def make_nws_request(url: str) -> dict[str, Any] | None:
    """ 异步函数
    用于发送 HTTP 请求到气象局 API
    包含完整的错误处理: HTTP 错误、请求错误和其他异常
    返回 JSON 格式的响应数据或 None(如果请求失败)
    """
    headers = {
        "User-Agent": USER_AGENT,
        "Accept": "application/geo+json"
    }
    # 创建异步HTTP客户端
    async with httpx.AsyncClient() as client:
        try:
            # 发送GET请求
            response = await client.get(url, headers=headers, timeout=30.0)
            # 检查响应状态码
            response.raise_for_status()
            # 返回JSON数据
            return response.json()
        except httpx.HTTPStatusError as e:
            print(f"HTTP error occurred: {e.response.status_code} {e.request.url}")
            return None
        except httpx.RequestError as e:
            print(f"Request failed: {e}")
            return None
        except Exception as e:
            print(f"Unexpected error: {e}")
            return None

def format_alert(feature: dict) -> str:
    """
    将天气预警数据格式化为可读的字符串
    """
    props = feature["properties"]   # 获取预警属性（从HTTP请求中的结果选取）
    return f"""
Event: {props.get('event', 'Unknown')}          # 事件
Area: {props.get('areaDesc', 'Unknown')}        # 地区描述
Severity: {props.get('severity', 'Unknown')}    # 严重性
Description: {props.get('description', 'No description available')} # 描述
Instructions: {props.get('instruction', 'No specific instructions provided')}  # 指示
"""

@mcp.tool()
async def get_alerts(state: str) -> str:
    '''
    美国某个州的天气预警信息
    Args:
        state: 两位字母的美国州代码 (例如 CA, NY)
    '''
    url = f"{NWS_API_BASE}/alerts/active/area/{state}"
    data = await make_nws_request(url)   # 请求天气预警数据

    # 数据有效性检查
    # 如果请求失败或返回数据不包含 features 字段
    if not data or "features" not in data:
        return "Unable to fetch alerts or no alerts found."

    # 如果 features 为空，则返回“该州没有活跃预警”
    if not data["features"]:
        return "No active alerts for this state."
    
    # 格式化预警信息
    alerts = [format_alert(feature) for feature in data["features"]]
    return "\n---\n".join(alerts)


@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
    """获取某个位置的天气预报.
    Args:
        latitude: 位置的纬度
        longitude: 位置的经度
    """
    # 1.首先获取预报网格 endpoint
    points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
    points_data = await make_nws_request(points_url)

    if not points_data:
        return "Unable to fetch forecast data for this location."

    # 2.从 points response 中获取预报 URL
    forecast_url = points_data["properties"]["forecast"]
    forecast_data = await make_nws_request(forecast_url)

    if not forecast_data:
        return "Unable to fetch detailed forecast."

    # 3.将 periods 格式化为可读的预报
    periods = forecast_data["properties"]["periods"]
    forecasts = []
    for period in periods[:5]:  # Only show next 5 periods
        forecast = f"""
{period['name']}:
Temperature: {period['temperature']}°{period['temperatureUnit']}  # 温度
Wind: {period['windSpeed']} {period['windDirection']}             # 风速和方向
Forecast: {period['detailedForecast']}                            # 详细预报
"""
        forecasts.append(forecast)

    return "\n---\n".join(forecasts)
    
    
if __name__ == "__main__":
    # Initialize and run the server
    mcp.run(transport='stdio')
